﻿// -----------------------------------------------------------------------
// <copyright file="WeeklyCalendar.cs" company="The Usual Dosage">
// © 2013 by Matthew M. Martin
// </copyright>
// -----------------------------------------------------------------------

namespace Cadence.NET.Calendars
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using Cadence.NET.BaseClasses;

    /// <summary>
    /// Describes the methods and properties of a week-based calendar.
    /// </summary>
    public class WeeklyCalendar : ICalendar
    {
        #region Properties

        private List<int> runWeeks;
        /// <summary>
        /// Gets or sets the run weeks.
        /// </summary>
        /// <value>
        /// The run weeks.
        /// </value>
        public List<int> RunWeeks
        {
            get
            {
                return runWeeks;
            }
            set
            {
                var invalidWeeks = value.Where(w => w <= 0 || w > 5);
                if (invalidWeeks != null && invalidWeeks.Count() > 0)
                {
                    throw new InvalidOperationException("Week must be a value between 1 and 5.");
                }
                else
                {
                    runWeeks = value;
                }
            }
        }

        private List<int> excludeWeeks;
        /// <summary>
        /// Gets or sets the Include weeks.
        /// </summary>
        /// <value>
        /// The Include weeks.
        /// </value>
        public List<int> ExcludeWeeks
        {
            get
            {
                return excludeWeeks;
            }
            set
            {
                var invalidWeeks = value.Where(w => w <= 0 || w > 5);
                if (invalidWeeks != null && invalidWeeks.Count() > 0)
                {
                    throw new InvalidOperationException("Week must be a value between 1 and 5.");
                }
                else
                {
                    excludeWeeks = value;
                }
            }
        }

        private List<int> overrideWeeks;
        /// <summary>
        /// Gets or sets the override weeks.
        /// </summary>
        /// <value>
        /// The override weeks.
        /// </value>
        public List<int> OverrideWeeks
        {
            get
            {
                return overrideWeeks;
            }
            set
            {
                var invalidWeeks = value.Where(w => w <= 0 || w > 5);
                if (invalidWeeks != null && invalidWeeks.Count() > 0)
                {
                    throw new InvalidOperationException("Week must be a value between 1 and 5.");
                }
                else
                {
                    overrideWeeks = value;
                }
            }
        }

        /// <summary>
        /// Gets or sets the timezone offset from UTC.
        /// </summary>
        /// <value>
        /// The timezone offset.
        /// </value>
        public int? TimezoneUTCOffset
        {
            get;
            set;
        }

        /// <summary>
        /// Gets the current date time.
        /// </summary>
        public DateTime CurrentDateTime
        {
            get
            {
                if (TimezoneUTCOffset.HasValue)
                    return DateTime.UtcNow.AddHours(TimezoneUTCOffset.Value);
                else
                    return DateTime.UtcNow;
            }
        }

        #endregion Properties

        #region Interface Implementation
        
        /// <summary>
        /// When implemented in a derived class, checks the time configured, and indicates whether this instance can run.
        /// </summary>
        /// <returns>
        ///   <c>true</c> if this instance can run; otherwise, <c>false</c>.
        /// </returns>
        public bool CanRun()
        {
            int week = CurrentDateTime.GetWeekOfMonth();

            if (OverrideWeeks != null && OverrideWeeks.Contains(week))
                return true;
            else if (ExcludeWeeks != null && ExcludeWeeks.Contains(week))
                return false;
            else if (RunWeeks.Contains(week))
                return true;
            else
                return false;
        }

        #endregion Interface Implementation
    }
}
